package cn.studyjava.verify.code12306.service.impl;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import cn.studyjava.verify.code12306.common.Const;
import cn.studyjava.verify.code12306.common.enums.VerifyEnum;
import cn.studyjava.verify.code12306.model.ImgVerify;
import cn.studyjava.verify.code12306.model.Space;
import cn.studyjava.verify.code12306.model.vo.AuthVO;
import cn.studyjava.verify.code12306.mybatis.entity.Auth;
import cn.studyjava.verify.code12306.service.IAuthService;
import cn.studyjava.verify.code12306.service.IGenerateCodeService;
import cn.studyjava.verify.code12306.service.IVerifyService;
import cn.studyjava.verify.code12306.util.GeneratorKey;
import cn.studyjava.verify.code12306.util.JsonUtil;
import cn.studyjava.verify.code12306.util.ThreadPoolExecutorUtil;

/**
 * <p>
 * Description:
 * </p>
 * 
 * @author: zsljava
 * @version 1.0.0
 * <p>
 * History:
 * -----------------------------------------------
 * @Date: 2017年10月16日 下午3:29:57
 * @author: zsljava
 * @version 1.0.0
 * @OP: Create
 * -----------------------------------------------
 * </p>
 *
 * @since
 * @see
 */
@Service("verifyService")
public class VerifyServiceImpl implements IVerifyService{
	
	private Logger log = LoggerFactory.getLogger(VerifyServiceImpl.class);
	
//	/**
//	 * EIGHT、SIX、NINE
//	 */
//	private static StyleEnum STYLE = StyleEnum.EIGHT;
	
	/**
	 * 临界值  redis中验证图片少于criticalityValue，生成createValue张
	 */
	@Value("${verify.img.criticalityValue}")
	private int criticalityValue; 
	
	/**
	 * 临界值  redis中验证图片少于criticalityValue，生成createValue张
	 */
	@Value("${verify.img.createValue}")
	private int createValue; 
	
	@Autowired
	private StringRedisTemplate redisTemplate;
	
	@Autowired
	private IGenerateCodeService generateCodeService;
	
	@Autowired
	private IAuthService authService;
	
	/**
	 * threadPoolExecutorUtil
	 */
	private static ThreadPoolExecutorUtil threadPoolExecutorUtil = new ThreadPoolExecutorUtil();
	
	@Override
	public ImgVerify getVerifyCode() {
		// 获取集合大小
		Long size = redisTemplate.opsForSet().size(Const.VERIFY_CODE_SET);
		// 如果小于临界值则生成createValue 张验证码
		if(size <= criticalityValue){
			createValue = createValue < 10 ? 10 : createValue;
			log.debug("验证码少于{}张，执行生成命令，生成{}", criticalityValue, createValue);
			for (int i = 0; i < 10; i++) {
				threadPoolExecutorUtil.execute(()->{
					generateCodeService.generate(createValue / 10);
				});
			}
		}
		if(size == 0){
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// pop 移除并返回集合中的一个随机元素。
		String value = redisTemplate.opsForSet().pop(Const.VERIFY_CODE_SET);
		if(StringUtils.isNotEmpty(value)){
			ImgVerify img = JsonUtil.json2pojo(value, ImgVerify.class);
			img.setVerifyStartTime(new Date());
			String newKey = Const.REDIS_ALREADY_PREFIX.concat(img.getVerifyCode());
			redisTemplate.opsForValue().set(newKey, JsonUtil.obj2json(img), Const.DEFAULT_VERIFY_TIME_SECONDS, TimeUnit.SECONDS);
			img.setSpace(null);
			return img;
		}
		return new ImgVerify();
	}

	@Override
	public AuthVO verify(String appId, String newKey, String offset, String ip) {
		long startTime = System.currentTimeMillis();
		Auth auth = new Auth();
		auth.setIp(ip);
		auth.setAppId(appId);
		auth.setAuthId(GeneratorKey.key());
		Date authStopTime = new Date();
		auth.setAuthStopTime(authStopTime);
		auth.setStatus(Const.VERIFY_STATUS_FAIL);
		boolean result = redisTemplate.hasKey(newKey);
		AuthVO av = new AuthVO();
		if(result){
			if (StringUtils.isEmpty(offset)) {
				auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_PARAMS_IS_NULL.getCode());
				return av;
			}
			ImgVerify verify = JsonUtil.json2pojo(redisTemplate.opsForValue().get(newKey),ImgVerify.class);
			redisTemplate.delete(newKey);
			
			auth.setAuthType(verify.getVerifyType());
			auth.setVerifyName(verify.getVerifyName());
			auth.setAuthStartTime(verify.getVerifyStartTime());
			auth.setVerifyCreateTime(verify.getVerifyStartTime());
			Long authTime = authStopTime.getTime() - verify.getVerifyStartTime().getTime();
			auth.setAuthTime(authTime.intValue() / 1000);
			List<Space> spaceList = verify.getSpace();
			String[] offsetArr = offset.split(",");
			// 用户选择验证码个数 小于 验证码个数
			if (spaceList.size() > offsetArr.length / 2) { 
				log.info("选择图片不完整");
				auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_CHOICE_ERROR.getCode());
				authService.addAuth(auth);
				BeanUtils.copyProperties(auth, av);
				return av;
			}
			
			Boolean flag = null;
			double x = 0;
			double y = 0;
			for (int i = 0; i < offsetArr.length; i++) {
				flag = false;
				x = Double.valueOf(offsetArr[i]) + Const.OFFSET;
				y = Double.valueOf(offsetArr[i + 1]) + Const.OFFSET;
				i++;
				for (Space space : spaceList) {
					if (space.getXleft() <= x && x <= space.getXright() && space.getYup() <= y && y <= space.getYdown()) {
						flag = true;
					}
				}
				
				if(!flag){
					auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_CHOICE_ERROR.getCode());
					authService.addAuth(auth);
					BeanUtils.copyProperties(auth, av);
					return av;
				}
			}
			
			auth.setStatus(Const.VERIFY_STATUS_SUCCESS);
			auth.setReasonCode(VerifyEnum.VERIFY_AUTH_SUCCESS.getCode());
			
		}else{ // 验证码不存在
			auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_CODE_NOT_EXIST.getCode());
		}
		authService.addAuth(auth);
		BeanUtils.copyProperties(auth, av);
		
		long endTime = System.currentTimeMillis();
		log.info("校验用时=>" + (endTime - startTime) + "ms");
		
		return av;

	}

}
